package org.hawk.gwt.ppc.parser.impl;

import java.io.InputStream;

import junit.framework.TestCase;

import org.hawk.gwt.ppc.parser.BlockDescriptor;
import org.hawk.gwt.ppc.parser.ClassDescriptor;
import org.hawk.gwt.ppc.parser.Descriptor;
import org.hawk.gwt.ppc.parser.DoWhileExpressionDescriptor;
import org.hawk.gwt.ppc.parser.ForExpressionDescriptor;
import org.hawk.gwt.ppc.parser.ForeachExpressionDescriptor;
import org.hawk.gwt.ppc.parser.IfExpressionDescriptor;
import org.hawk.gwt.ppc.parser.JavaParser;
import org.hawk.gwt.ppc.parser.KeywordExpressionDescriptor;
import org.hawk.gwt.ppc.parser.LiteralExpressionDescriptor;
import org.hawk.gwt.ppc.parser.MethodCallDescriptor;
import org.hawk.gwt.ppc.parser.NameExpressionDescriptor;
import org.hawk.gwt.ppc.parser.NewOperatorExpressionDescriptor;
import org.hawk.gwt.ppc.parser.OperatorExpressionDescriptor;
import org.hawk.gwt.ppc.parser.SwitchExpressionDescriptor;
import org.hawk.gwt.ppc.parser.SynchronizedBlockDescriptor;
import org.hawk.gwt.ppc.parser.TryCatchFinallyExpressionDescriptor;
import org.hawk.gwt.ppc.parser.VariableDescriptor;
import org.hawk.gwt.ppc.parser.WhileExpressionDescriptor;
import org.hawk.gwt.ppc.parser.impl.mock.BlockExpressionMock;
import org.hawk.gwt.ppc.utils.Name;
import org.hawk.gwt.ppc.utils.PreprocessorException;

public class BlockDescriptorTestCase extends TestCase {
	
	public void testIfElseIfElse() throws PreprocessorException {
		BlockDescriptor block = getBlock(BlockExpressionMock.class, 0);
		
		Descriptor descr = block.get(0);
		assertTrue(descr instanceof IfExpressionDescriptor);
		IfExpressionDescriptor ifdescr = (IfExpressionDescriptor) descr;
		
		assertNotNull(ifdescr.getCondition());
		assertNotNull(ifdescr.getExpression());
		assertNull(ifdescr.getElseExpression());
		
		assertTrue(ifdescr.getCondition() instanceof NameExpressionDescriptor);
		assertEquals("aaa", ((NameExpressionDescriptor)ifdescr.getCondition()).getName());
		assertTrue(ifdescr.getExpression() instanceof BlockDescriptor);
		
		
		Descriptor descr1 = block.get(1);
		assertTrue(descr1 instanceof IfExpressionDescriptor);
		IfExpressionDescriptor ifdescr1 = (IfExpressionDescriptor) descr1;
		
		assertNotNull(ifdescr1.getCondition());
		assertNotNull(ifdescr1.getExpression());
		assertNotNull(ifdescr1.getElseExpression());
		
		assertTrue(ifdescr1.getCondition() instanceof NameExpressionDescriptor);
		assertEquals("bbb", ((NameExpressionDescriptor)ifdescr1.getCondition()).getName());
		assertTrue(ifdescr1.getExpression() instanceof BlockDescriptor);
		assertTrue(ifdescr1.getElseExpression() instanceof IfExpressionDescriptor);
		
		
		IfExpressionDescriptor ifdescr11 = (IfExpressionDescriptor) ifdescr1.getElseExpression();
		
		assertNotNull(ifdescr11.getCondition());
		assertNotNull(ifdescr11.getExpression());
		assertNull(ifdescr11.getElseExpression());
		
		assertTrue(ifdescr11.getCondition() instanceof NameExpressionDescriptor);
		assertEquals("aaa", ((NameExpressionDescriptor)ifdescr11.getCondition()).getName());
		assertTrue(ifdescr11.getExpression() instanceof BlockDescriptor);
		
		Descriptor descr2 = block.get(2);
		assertTrue(descr2 instanceof IfExpressionDescriptor);
		IfExpressionDescriptor ifdescr2 = (IfExpressionDescriptor) descr2;
		
		assertNotNull(ifdescr2.getCondition());
		assertNotNull(ifdescr2.getExpression());
		assertNotNull(ifdescr2.getElseExpression());
		
		assertTrue(ifdescr2.getCondition() instanceof NameExpressionDescriptor);
		assertEquals("aaa", ((NameExpressionDescriptor)ifdescr2.getCondition()).getName());
		assertTrue(ifdescr2.getExpression() instanceof BlockDescriptor);
		assertTrue(ifdescr2.getElseExpression() instanceof BlockDescriptor);
		
		
		Descriptor descr3 = block.get(3);
		assertTrue(descr3 instanceof IfExpressionDescriptor);
		IfExpressionDescriptor ifdescr3 = (IfExpressionDescriptor) descr3;
		
		assertNotNull(ifdescr3.getCondition());
		assertNotNull(ifdescr3.getExpression());
		assertNotNull(ifdescr3.getElseExpression());
		
		assertTrue(ifdescr3.getCondition() instanceof NameExpressionDescriptor);
		assertEquals("bbb", ((NameExpressionDescriptor)ifdescr3.getCondition()).getName());
		assertTrue(ifdescr3.getExpression() instanceof BlockDescriptor);
		assertTrue(ifdescr3.getElseExpression() instanceof IfExpressionDescriptor);
		
		IfExpressionDescriptor ifdescr31 = (IfExpressionDescriptor) ifdescr3.getElseExpression();
		
		assertNotNull(ifdescr31.getCondition());
		assertNotNull(ifdescr31.getExpression());
		assertNotNull(ifdescr31.getElseExpression());
		
		assertTrue(ifdescr31.getCondition() instanceof NameExpressionDescriptor);
		assertEquals("aaa", ((NameExpressionDescriptor)ifdescr31.getCondition()).getName());
		assertTrue(ifdescr31.getExpression() instanceof BlockDescriptor);
		assertTrue(ifdescr31.getElseExpression() instanceof BlockDescriptor);
		
		Descriptor descr4 = block.get(4);
		assertTrue(descr4 instanceof IfExpressionDescriptor);
		IfExpressionDescriptor ifdescr4 = (IfExpressionDescriptor) descr4;
		
		assertNotNull(ifdescr4.getCondition());
		assertNotNull(ifdescr4.getExpression());
		assertNotNull(ifdescr4.getElseExpression());
		
		assertTrue(ifdescr4.getCondition() instanceof NameExpressionDescriptor);
		assertEquals("bbb", ((NameExpressionDescriptor)ifdescr4.getCondition()).getName());
		assertTrue(ifdescr4.getExpression() instanceof MethodCallDescriptor);
		assertTrue(ifdescr4.getElseExpression() instanceof IfExpressionDescriptor);
		
		IfExpressionDescriptor ifdescr41 = (IfExpressionDescriptor) ifdescr4.getElseExpression();
		
		assertNotNull(ifdescr41.getCondition());
		assertNotNull(ifdescr41.getExpression());
		assertNotNull(ifdescr41.getElseExpression());
		
		assertTrue(ifdescr41.getCondition() instanceof OperatorExpressionDescriptor);
		assertTrue(ifdescr41.getExpression() instanceof MethodCallDescriptor);
		assertTrue(ifdescr41.getElseExpression() instanceof IfExpressionDescriptor);
		
		IfExpressionDescriptor ifdescr42 = (IfExpressionDescriptor) ifdescr41.getElseExpression();
		
		assertNotNull(ifdescr42.getCondition());
		assertNotNull(ifdescr42.getExpression());
		assertNotNull(ifdescr42.getElseExpression());
		
		assertTrue(ifdescr42.getCondition() instanceof OperatorExpressionDescriptor);
		assertTrue(ifdescr42.getExpression() instanceof MethodCallDescriptor);
		assertTrue(ifdescr42.getElseExpression() instanceof MethodCallDescriptor);
	}
	
	public void testSwitchCase() throws PreprocessorException {
		BlockDescriptor block = getBlock(BlockExpressionMock.class, 1);
		
		Descriptor desc = block.get(1);
		
		assertTrue(desc instanceof SwitchExpressionDescriptor);
		SwitchExpressionDescriptor switchDesc = (SwitchExpressionDescriptor)desc;
		assertEquals(2, switchDesc.getCases().size());
		
		assertTrue(switchDesc.getSwitchExpression() instanceof NameExpressionDescriptor);
		
		assertTrue(switchDesc.getCases().get(0) instanceof LiteralExpressionDescriptor);
		assertEquals(3, ((LiteralExpressionDescriptor)switchDesc.getCases().get(0)).asInt());
		assertTrue(switchDesc.getCaseExpression(switchDesc.getCases().get(0)).get(0) instanceof KeywordExpressionDescriptor);
		
		assertTrue(switchDesc.getCases().get(1) instanceof NameExpressionDescriptor);
		assertEquals("THEVALUE", ((NameExpressionDescriptor)switchDesc.getCases().get(1)).getName());
		assertTrue(switchDesc.getCaseExpression(switchDesc.getCases().get(1)).get(0) instanceof KeywordExpressionDescriptor);
		
		assertNotNull(switchDesc.getDefault());
		assertTrue(switchDesc.getDefault().get(0) instanceof BlockDescriptor);
		
		Descriptor desc2 = block.get(2);
		
		assertTrue(desc2 instanceof SwitchExpressionDescriptor);
		SwitchExpressionDescriptor switchDesc2 = (SwitchExpressionDescriptor)desc2;
		assertEquals(1, switchDesc2.getCases().size());
		
		assertTrue(switchDesc2.getSwitchExpression() instanceof NameExpressionDescriptor);
		
		assertTrue(switchDesc2.getCases().get(0) instanceof LiteralExpressionDescriptor);
		assertEquals(10, ((LiteralExpressionDescriptor)switchDesc2.getCases().get(0)).asInt());
		assertTrue(switchDesc2.getCaseExpression(switchDesc2.getCases().get(0)).get(0) instanceof BlockDescriptor);
		
		assertNull(switchDesc2.getDefault());
		
		Descriptor desc3 = block.get(3);
		
		assertTrue(desc3 instanceof SwitchExpressionDescriptor);
		SwitchExpressionDescriptor switchDesc3 = (SwitchExpressionDescriptor)desc3;
		assertEquals(0, switchDesc3.getCases().size());
		
		assertTrue(switchDesc3.getSwitchExpression() instanceof NameExpressionDescriptor);
		
		assertNotNull(switchDesc3.getDefault());
		assertTrue(switchDesc3.getDefault().isEmpty());
		
		Descriptor desc4 = block.get(4);
		
		assertTrue(desc4 instanceof SwitchExpressionDescriptor);
		SwitchExpressionDescriptor switchDesc4 = (SwitchExpressionDescriptor)desc4;
		assertEquals(0, switchDesc4.getCases().size());
		
		assertTrue(switchDesc4.getSwitchExpression() instanceof NameExpressionDescriptor);
		
		assertNull(switchDesc4.getDefault());
	}
	
	public void testWhile() throws PreprocessorException {
		BlockDescriptor block = getBlock(BlockExpressionMock.class, 2);
		
		Descriptor desc = block.get(0);
		
		assertTrue(desc instanceof WhileExpressionDescriptor);
		WhileExpressionDescriptor whileDesc = (WhileExpressionDescriptor)desc;
		
		assertNotNull(whileDesc.getCondition());
		assertTrue(whileDesc.getCondition() instanceof MethodCallDescriptor);
		
		assertNotNull(whileDesc.getExpression());
		assertTrue(whileDesc.getExpression() instanceof BlockDescriptor);
		
		desc = block.get(1);
		
		assertTrue(desc instanceof WhileExpressionDescriptor);
		WhileExpressionDescriptor whileDesc1 = (WhileExpressionDescriptor)desc;
		
		assertNotNull(whileDesc1.getCondition());
		assertTrue(whileDesc1.getCondition() instanceof MethodCallDescriptor);
		
		assertNotNull(whileDesc1.getExpression());
		assertTrue(whileDesc1.getExpression() instanceof MethodCallDescriptor);
		
	}
	
	public void testFor() throws PreprocessorException {
		BlockDescriptor block = getBlock(BlockExpressionMock.class, 3);
		
		Descriptor desc0 = block.get(0);
		assertTrue(desc0 instanceof ForExpressionDescriptor);
	
		ForExpressionDescriptor forexpr0 = (ForExpressionDescriptor)desc0;
		
		assertTrue(forexpr0.getInitializer() instanceof OperatorExpressionDescriptor);
		assertEquals("=", ((OperatorExpressionDescriptor)forexpr0.getInitializer()).getOperator());
		
		assertTrue(forexpr0.getCondition() instanceof OperatorExpressionDescriptor);
		assertEquals("<", ((OperatorExpressionDescriptor)forexpr0.getCondition()).getOperator());
		
		assertTrue(forexpr0.getPostExpression() instanceof OperatorExpressionDescriptor);
		assertEquals("++", ((OperatorExpressionDescriptor)forexpr0.getPostExpression()).getOperator());
		
		assertTrue(forexpr0.getExpression() instanceof BlockDescriptor);
		
		Descriptor desc1 = block.get(1);
		assertTrue(desc1 instanceof ForExpressionDescriptor);
	
		ForExpressionDescriptor forexpr1 = (ForExpressionDescriptor)desc1;
		
		assertTrue(forexpr1.getInitializer() instanceof OperatorExpressionDescriptor);
		assertEquals("=", ((OperatorExpressionDescriptor)forexpr1.getInitializer()).getOperator());
		
		assertTrue(forexpr1.getCondition() instanceof OperatorExpressionDescriptor);
		assertEquals("<", ((OperatorExpressionDescriptor)forexpr1.getCondition()).getOperator());
		
		assertTrue(forexpr1.getPostExpression() instanceof OperatorExpressionDescriptor);
		assertEquals("++", ((OperatorExpressionDescriptor)forexpr1.getPostExpression()).getOperator());
		
		assertTrue(forexpr1.getExpression() instanceof MethodCallDescriptor);
	}
	
	public void testForeach() throws PreprocessorException {
		BlockDescriptor block = getBlock(BlockExpressionMock.class, 4);
		
		Descriptor desc0 = block.get(0);
		assertTrue(desc0 instanceof ForeachExpressionDescriptor);
		
		ForeachExpressionDescriptor foreach0 = (ForeachExpressionDescriptor)desc0;
		assertTrue(foreach0.getCollection() instanceof NameExpressionDescriptor);
		assertEquals("values", ((NameExpressionDescriptor)foreach0.getCollection()).getName());
		
		assertTrue(foreach0.getVariable() instanceof VariableDescriptor);
		assertEquals("i", ((VariableDescriptor)foreach0.getVariable()).getName());
		assertEquals("int", ((VariableDescriptor)foreach0.getVariable()).getType());
		
		assertTrue(foreach0.getExpression() instanceof MethodCallDescriptor);
		
		Descriptor desc1 = block.get(1);
		assertTrue(desc1 instanceof ForeachExpressionDescriptor);
		
		ForeachExpressionDescriptor foreach1 = (ForeachExpressionDescriptor)desc1;
		assertTrue(foreach1.getCollection() instanceof NameExpressionDescriptor);
		assertEquals("values", ((NameExpressionDescriptor)foreach1.getCollection()).getName());
		
		assertTrue(foreach1.getVariable() instanceof VariableDescriptor);
		assertEquals("i", ((VariableDescriptor)foreach1.getVariable()).getName());
		assertEquals("int", ((VariableDescriptor)foreach1.getVariable()).getType());
		
		assertTrue(foreach1.getExpression() instanceof BlockDescriptor);
	}
	
	public void testDoWhile() throws PreprocessorException {
		BlockDescriptor block = getBlock(BlockExpressionMock.class, 5);
		
		Descriptor desc0 = block.get(0);
		assertTrue(desc0 instanceof DoWhileExpressionDescriptor);
		
		DoWhileExpressionDescriptor do0 = (DoWhileExpressionDescriptor)desc0;
		assertTrue(do0.getCondition() instanceof MethodCallDescriptor);
		assertTrue(do0.getExpression() instanceof BlockDescriptor);
		
		Descriptor desc1 = block.get(1);
		assertTrue(desc1 instanceof DoWhileExpressionDescriptor);
		
		DoWhileExpressionDescriptor do1 = (DoWhileExpressionDescriptor)desc1;
		assertTrue(do1.getCondition() instanceof MethodCallDescriptor);
		assertTrue(do1.getExpression() instanceof MethodCallDescriptor);
	}
	
	public void testTryCatchFinally() throws PreprocessorException {
		BlockDescriptor block = getBlock(BlockExpressionMock.class, 6);
		
		Descriptor desc0 = block.get(0);
		assertTrue(desc0 instanceof TryCatchFinallyExpressionDescriptor);
		TryCatchFinallyExpressionDescriptor try0 = (TryCatchFinallyExpressionDescriptor)desc0;
		
		assertNotNull(try0.getTryBlock());
		assertEquals(1, try0.getTryBlock().size());
		
		assertEquals(2, try0.getCatchClasuses().size());
		
		assertTrue(try0.getCatchClasuses().get(0) instanceof VariableDescriptor);
		assertEquals("ex", ((VariableDescriptor)try0.getCatchClasuses().get(0)).getName());
		assertEquals("RuntimeException", ((VariableDescriptor)try0.getCatchClasuses().get(0)).getType());
		assertEquals(1, try0.getCatchBlock(try0.getCatchClasuses().get(0)).size());
		
		assertTrue(try0.getCatchClasuses().get(1) instanceof VariableDescriptor);
		assertEquals("err", ((VariableDescriptor)try0.getCatchClasuses().get(1)).getName());
		assertEquals("InternalError", ((VariableDescriptor)try0.getCatchClasuses().get(1)).getType());
		assertEquals(1, try0.getCatchBlock(try0.getCatchClasuses().get(1)).size());
		
		assertNotNull(try0.getFinallyBlock());
		assertEquals(1, try0.getFinallyBlock().size());
		
		Descriptor desc1 = block.get(1);
		assertTrue(desc1 instanceof TryCatchFinallyExpressionDescriptor);
		TryCatchFinallyExpressionDescriptor try1 = (TryCatchFinallyExpressionDescriptor)desc1;
		
		assertNotNull(try1.getTryBlock());
		assertEquals(1, try1.getTryBlock().size());
		
		assertEquals(0, try1.getCatchClasuses().size());
	
		assertNotNull(try1.getFinallyBlock());
		assertEquals(1, try1.getFinallyBlock().size());
		
		Descriptor desc2 = block.get(2);
		assertTrue(desc2 instanceof TryCatchFinallyExpressionDescriptor);
		TryCatchFinallyExpressionDescriptor try2 = (TryCatchFinallyExpressionDescriptor)desc2;
		
		assertNotNull(try2.getTryBlock());
		assertEquals(2, try2.getTryBlock().size());
		
		assertEquals(1, try2.getCatchClasuses().size());
		
		assertTrue(try2.getCatchClasuses().get(0) instanceof VariableDescriptor);
		assertEquals("exception", ((VariableDescriptor)try2.getCatchClasuses().get(0)).getName());
		assertEquals("java.lang.RuntimeException", ((VariableDescriptor)try2.getCatchClasuses().get(0)).getType());
		assertEquals("final", ((VariableDescriptor)try2.getCatchClasuses().get(0)).getModifiers().get(0));
		assertEquals(2, try2.getCatchBlock(try2.getCatchClasuses().get(0)).size());
		
		assertNull(try2.getFinallyBlock());
	}
	
	public void testInternalBlock() throws PreprocessorException {
		BlockDescriptor block = getBlock(BlockExpressionMock.class, 7);
		
		Descriptor desc0 = block.get(0);
		
		assertTrue(desc0 instanceof SynchronizedBlockDescriptor);
		SynchronizedBlockDescriptor sync0 = (SynchronizedBlockDescriptor)desc0;
		assertTrue(sync0.getTarget() instanceof NameExpressionDescriptor);
		assertEquals("this", ((NameExpressionDescriptor)sync0.getTarget()).getName());
		
		Descriptor desc1 = block.get(1);
		assertTrue(desc0 instanceof BlockDescriptor);
		assertEquals(1, ((BlockDescriptor)desc1).size());
		
		assertEquals(2, block.size());
	}
	
	public void testLabels() throws PreprocessorException {
		BlockDescriptor block = getBlock(BlockExpressionMock.class, 8);
		
		Descriptor desc0 = block.get(0);
		
		assertTrue(desc0 instanceof BlockDescriptor);
		BlockDescriptor block0 = (BlockDescriptor)desc0;
		assertEquals(2, block0.getLabels().size());
		assertEquals("label0", block0.getLabels().get(0));
		assertEquals("label1", block0.getLabels().get(1));
		
		Descriptor desc1 = block0.get(0);
		assertTrue(desc1 instanceof TryCatchFinallyExpressionDescriptor);
		TryCatchFinallyExpressionDescriptor block1 = (TryCatchFinallyExpressionDescriptor)desc1;
		assertEquals(1, block1.getLabels().size());
		assertEquals("label2", block1.getLabels().get(0));
		
		Descriptor desc2 = block1.getTryBlock().get(0);
		assertTrue(desc2 instanceof WhileExpressionDescriptor);
		WhileExpressionDescriptor block2 = (WhileExpressionDescriptor)desc2;
		assertEquals(1, block2.getLabels().size());
		assertEquals("label3", block2.getLabels().get(0));
		
		Descriptor desc3 = ((BlockDescriptor)block2.getExpression()).get(0);
		assertTrue(desc3 instanceof SynchronizedBlockDescriptor);
		SynchronizedBlockDescriptor block3 = (SynchronizedBlockDescriptor)desc3;
		assertEquals(1, block3.getLabels().size());
		assertEquals("label4", block3.getLabels().get(0));
		
		Descriptor desc4 = block3.get(0);
		assertTrue(desc4 instanceof SwitchExpressionDescriptor);
		SwitchExpressionDescriptor block4 = (SwitchExpressionDescriptor)desc4;
		assertEquals(1, block4.getLabels().size());
		assertEquals("label5", block4.getLabels().get(0));
	}
	
	public void testLocalClass() throws PreprocessorException {
		BlockDescriptor block = getBlock(BlockExpressionMock.class, 9);
		Descriptor descr = block.get(1);
		assertTrue(descr instanceof ClassDescriptor);
		ClassDescriptor cls = (ClassDescriptor) descr;
		assertEquals(1, cls.getModifiers().size());
		assertEquals("final", cls.getModifiers().get(0));
		assertEquals("Local", cls.getName());
		assertEquals(1, cls.getImplementsSection().size());
		assertEquals("Runnable", cls.getImplementsSection().get(0));
		assertEquals(1, cls.getExtendsSection().size());
		assertEquals("Object", cls.getExtendsSection().get(0));
	}
	
	public void testAnonymousClass() throws PreprocessorException {
		BlockDescriptor block = getBlock(BlockExpressionMock.class, 9);
		Descriptor descr = block.get(0);
		assertTrue(descr instanceof OperatorExpressionDescriptor);
		descr = ((OperatorExpressionDescriptor)descr).getRightOperand();
		assertTrue(descr instanceof NewOperatorExpressionDescriptor);
		NewOperatorExpressionDescriptor new0 = (NewOperatorExpressionDescriptor)descr;
		
		assertNotNull(new0.getAnonymousClass());
		assertEquals("", new0.getAnonymousClass().getName());
		assertEquals(1, new0.getAnonymousClass().getExtendsSection().size());
		assertEquals("Callable<Integer>", new0.getAnonymousClass().getExtendsSection().get(0));
		assertTrue(new0.getAnonymousClass().getImplementsSection().isEmpty());
	}

	private BlockDescriptor getBlock(Class<?> clazz, int index) throws PreprocessorException {
		InputStream cu = getClass().getClassLoader().getResourceAsStream(Name.javaToFs(clazz.getCanonicalName()));
		try {
			JavaParser parser = JavaParser.create(cu);
			return parser.parse().getTopClasses().get(0).getMethods().get(index).getBody();
		} finally {
			try {
				cu.close();
			} catch(Exception ex) {
			}
		}
	}
}
